/*! \file MemoryMappedFilePS.cpp
 *	\brief
 *
 *	created:	2010/11/23
 *	created:	23:11:2010   10:13
 *	filename: 	C:\src\tactics-engine\libs\io\unix\MemoryMappedFile.cpp
 *	file path:	C:\src\tactics-engine\libs\io
 *	file base: MemoryMappedFile
 *	file ext:	cpp
 *	author:		Vitalii Trubchaninov
 *				vitalii.trubchaninov@ubisoft.com
 */

#include "io/stdafx.h"

#include <sys/mman.h>
#include <sys/stat.h>

#include "io/unix/MemoryMappedFile_unix.h"
#include "utils/unix/FileHandle.h"
#include "utils/UnicodeConverter.h"

namespace tt{
namespace io{

namespace impl{

///////////////////////////////////////////////////////////////////////////////////
MemoryMappedHandle::~MemoryMappedHandle()
{
	Reset();
}

void MemoryMappedHandle::Reset()
{
	if(!m_Data)
		return;

	munmap(m_Data, m_Size);
}

} //namespace impl

///////////////////////////////////////////////////////////////////////////////////
MemoryMappedFilePS::MemoryMappedFilePS()
: m_FileMappingName()
, m_FileName()
, m_Mode(MemoryMappedFileMode_READONLY)
, m_File()
, m_Data()
{

}

MemoryMappedFilePS::MemoryMappedFilePS(const std::wstring& fileMappingName)
: m_FileMappingName(fileMappingName)
, m_FileName()
, m_Mode(MemoryMappedFileMode_READONLY)
, m_File()
, m_Data()
{

}

MemoryMappedFilePS::~MemoryMappedFilePS()
{
	Close();
}

bool MemoryMappedFilePS::Open( const std::wstring& fileName, MemoryMappedFileMode mode )
{
	m_FileName = fileName;
	m_Mode = mode;

	if(!m_FileMappingName.empty() && Open())
	{
		//MG_LOG_DEBUG("MemoryMappedFilePS (%s) already Created - using existing");
		return true;
	}

	if(Create())
		return true;

	return false;
}

void MemoryMappedFilePS::Close()
{
	m_Data.Reset();
	m_File.Reset();
}

//////////////////////////////////////////////////////////////////////////
bool MemoryMappedFilePS::Open()
{
	return false;
}

bool MemoryMappedFilePS::Create()
{
	//MG_LOG_DEBUG("MemoryMappedFilePS::Creating");

	String utf8FileName = utils::to_utf8_1024(m_FileName);
	utils::FileHandle file( open(utf8FileName.c_str(), desireAccessFile() ) );
	if (!file)
	{
		//MG_LOG_FATAL("MemoryMappedFilePS: CreateFileW failed.");
		return false;
	}

	size_t fileSize = GetFileSize(file);
	if(fileSize == 0)
		return false;

	impl::MemoryMappedHandle mappedData( mmap(0, fileSize, protectMapping(), shareModeMapping(), file, 0 /*offset*/), fileSize );
	if (!mappedData)
	{
		//MG_LOG_FATAL("MemoryMappedFilePS: CreateFileMappingW failed.");
		return false;
	}

	m_File.Swap(file);
	m_Data.Swap(mappedData);

	//MG_LOG_DEBUG("MemoryMappedFilePS::Created");

	return true;
}

size_t MemoryMappedFilePS::GetFileSize( const utils::FileHandle& file )
{
	struct stat fStat;
	if (fstat(file, &fStat) == -1)
	{
		//MG_LOG_FATAL("MemoryMappedFilePS: GetFileSize failed.");
		return 0;
	}

	return fStat.st_size;
}

size_t MemoryMappedFilePS::GetFileSize(const std::wstring& fileName)
{
	struct stat fStat;
	String utf8FileName = utils::to_utf8_1024(fileName);
	if (stat(utf8FileName.c_str(), &fStat) == -1)
	{
		//MG_LOG_FATAL("MemoryMappedFilePS: GetFileSize failed.");
		return 0;
	}

	return fStat.st_size;
}

UInt MemoryMappedFilePS::desireAccessFile() const
{
	return Writeable() ?
		0 :
		O_RDONLY;
}

UInt MemoryMappedFilePS::shareModeMapping() const
{
	return Writeable() ?
		0 :
		MAP_SHARED;
}

UInt MemoryMappedFilePS::desireAccessMapping() const
{
	return Writeable() ?
		0 :
		0;
}

UInt MemoryMappedFilePS::protectMapping() const
{
	return Writeable() ?
		0 :
		PROT_READ;
}

} //namespace io
} //namespace protection
